#include "ScriptEngine.hpp"

/** 
* Creates a new script engine with its own lua state.
*/
ScriptEngine::ScriptEngine(){
    luaState = luaL_newstate();
    luaL_openlibs(luaState);
    luabind::open(luaState);
}

/** 
* Registers a global C function.
*/
void ScriptEngine::registerFunction(const char* name, lua_CFunction function){
    lua_register(luaState, name, function);
}

/** 
* Loads a script file into the lua state.
*/
void ScriptEngine::loadScript(const char* name){

    int loadResult = luaL_loadfile(luaState, name);
    if(loadResult != 0){
        const char* error = lua_tostring(luaState, -1);
        std::cout << error << std::endl;
    }else{
        //Primer run to make sure script is runnable.
        int runResult = lua_pcall(luaState, 0, 0, 0);
        if(runResult != 0){
            const char* error = lua_tostring(luaState, -1);
            std::cout << error << std::endl;
        }
    }
}

/** 
 * Pushes onto the stack a scriptable object.
 */
void ScriptEngine::pushScriptable(Scriptable* scriptable){
    scriptable->push(luaState);
}

/**
 * Push a string onto the stack.
 * Used to put string value as an argument.
 * @param str String to push onto stack.
 */
void ScriptEngine::pushString(const char* str){
    luabind::object o = luabind::object(luaState, str);
    o.push(luaState);
}

/**
 * Get a boolean value from the stack.
 * Used to retrieve return value of a function call.
 * @return Boolean value that has been returned from a function.
 */
bool ScriptEngine::getBool(){
    if(lua_toboolean(luaState, -1))
        return true;
    return false;
}


/** 
* Loads a function to prepare execution.
*/
void ScriptEngine::loadFunction(const char* name){
    lua_getglobal(luaState, name);
}

/** 
* Loads and runs the given function.
*/
bool ScriptEngine::loadAndRun(const char* name){
    loadFunction(name);
    if (lua_pcall(luaState, 0, 0, 0)){
        const char* error = lua_tostring(luaState, -1);
        std::cout << "Run: " << error << std::endl;
        return false;
    }
    return true;
}

/** 
* Runs a loaded function.
*/
bool ScriptEngine::run(int nargs, int nret){
    if (lua_pcall(luaState, nargs, nret, 0)){
        const char* error = lua_tostring(luaState, -1);
        std::cout << "Run: " << error << std::endl;
        return false;
    }
    return true;
}

/** 
* Registers a Scriptable class in lua.
*/
void ScriptEngine::registerClass(Scriptable* scriptable){
    scriptable->bind(luaState);
}

/** 
* Closes lua state
*/
ScriptEngine::~ScriptEngine(){
    lua_close(luaState);
}